package com.changgou.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.changgou.entity.Result;
import com.changgou.goods.feign.SkuFeign;
import com.changgou.goods.feign.SpuFeign;
import com.changgou.goods.pojo.Sku;
import com.changgou.goods.pojo.Spu;
import com.changgou.search.dao.SkuMapper;
import com.changgou.search.pojo.SkuInfo;
import com.changgou.search.service.SkuService;
import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 戴金华
 * @date 2019-12-07 16:15
 */
@Service
public class SkuServiceImpl implements SkuService {

    @Autowired
    private SkuFeign skuFeign;

    @Autowired
    private SkuMapper skuMapper;

    //设置每页显示条数
    public static final Integer PAGE_SIZE = 20;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    /**
     * 将数据库数据导入到es中
     */
    @Override
    public void importData() {
        //调用feign查询数据的所有数据
        Result<List<Sku>> skuResult = skuFeign.findAll();
        //将skuResult 转换为list<skuInfo>
        List<SkuInfo> skuInfos = JSON.parseArray(JSON.toJSONString(skuResult.getData()), SkuInfo.class);

        for (SkuInfo skuInfo : skuInfos) {
            Map<String, Object> specMap = JSON.parseObject(skuInfo.getSpec(), Map.class);
            skuInfo.setSpecMap(specMap);
        }
        //调用skuMapper存入es中
        skuMapper.saveAll(skuInfos);
    }


    /**
     * 根据id插入索引库
     *
     * @param spuId
     */
    @Override
    public void importDataById(String spuId) {
        Result<List<Sku>> result = skuFeign.findListBySpuId(spuId);
        List<Sku> skuList = result.getData();
        if (skuList.size() <= 0 || skuList == null) {
            throw new RuntimeException("当前商品无数据,无法导入");
        }
        //将数据转换成json
        String jsonSkuList = JSON.toJSONString(skuList);
        //将json转换哼索引库对象
        List<SkuInfo> skuInfos = JSON.parseArray(jsonSkuList, SkuInfo.class);
        //遍历
        for (SkuInfo skuInfo : skuInfos) {
            //将规格转换位map
            Map specMap = JSON.parseObject(skuInfo.getSpec(), Map.class);
            skuInfo.setSpecMap(specMap);
        }
        skuMapper.saveAll(skuInfos);
    }

    /**
     * 根据关键字进行查询
     *
     * @param searchMap
     * @return
     */
    @Override
    public Map<String, Object> search(Map<String, String> searchMap) {

        String keyword = searchMap.get("keyword");
        String brand = searchMap.get("brand");
        String category = searchMap.get("category");
        String price = searchMap.get("price");
        String pageNum = searchMap.get("pageNum");
        String sortRule = searchMap.get("sortRule");
        String sortField = searchMap.get("sortField");
        List<String> specList = null;
        List<String> brandList = null;
        List<String> categoryList = null;
        //原生的搜索类实现
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        //组合条件查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (searchMap != null && searchMap.size() > 0) {
            //0 关键字
            if (StringUtils.isNotEmpty(keyword)) {
                boolQueryBuilder.must(QueryBuilders.termQuery("name", keyword));
            }
            //1 品牌
            if (StringUtils.isNotEmpty(brand)) {
                boolQueryBuilder.filter(QueryBuilders.termQuery("brandName", brand));
            }
            //2 分类
            if (StringUtils.isNotEmpty(category)) {
                boolQueryBuilder.filter(QueryBuilders.termQuery("categoryName", category));
            }
            //3 规格
            for (String key : searchMap.keySet()) {
                if (key.startsWith("spec.")) {
                    String value = searchMap.get(key).replace("%2B", "+");
                    boolQueryBuilder.filter(QueryBuilders.termQuery("specMap." + key.substring(5) + ".keyword", value));
                }
            }

            //4 价格
            if (StringUtils.isNotEmpty(price)) {
                String[] priceArray = price.split("-");
                if (priceArray.length == 2) {
                    boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gte(Integer.parseInt(priceArray[0])).lte(Integer.parseInt(priceArray[1])));
                } else {
                    boolQueryBuilder.must(QueryBuilders.rangeQuery("price").lte(Integer.parseInt(priceArray[0])));
                }
            }

            // 4.1 排序
            if (StringUtils.isNotEmpty(sortField)){
                if ("".equals(sortRule)){
                    sortRule = "ASC";
                }
                if ("ASC".equals(sortRule)){
                    builder.withSort(SortBuilders.fieldSort(sortField).order(SortOrder.ASC));
                }else{
                    builder.withSort(SortBuilders.fieldSort(sortField).order(SortOrder.DESC));
                }
            }
        }
        //5 原生搜索类
        builder.withQuery(boolQueryBuilder);

        //6 分类的聚合查询
        if (StringUtils.isEmpty(category)) {
            //如果搜索条件中 不包含分类的查询 则对分类聚合查询
            builder.addAggregation(AggregationBuilders.terms("category").field("categoryName").size(100));
        }
        //7 品牌的聚合查询
        if (StringUtils.isEmpty(brand)) {
            //如果搜索条件中 不包含品牌的查询 则对品牌聚合查询
            builder.addAggregation(AggregationBuilders.terms("brand").field("brandName").size(100));
        }
        //8 规格聚合查询
        builder.addAggregation(AggregationBuilders.terms("skuSpec").field("spec.keyword").size(100));
        if (!ifHasSpecCondition(searchMap)) {
            //如果搜索条件中 不包含规格的查询 则对规格做聚合查询
        }

        //9 分页查询 (默认第一页 每页显示20条)
        if (null == pageNum) {
            pageNum = "1";
        }
        builder.withPageable(PageRequest.of(Integer.parseInt(pageNum) - 1, PAGE_SIZE));

        //9.1 高亮查询
        HighlightBuilder.Field field = new HighlightBuilder
                .Field("name")
                .preTags("<span style='color'>")
                .postTags("</span>");
        builder.withHighlightFields(field);
        //10 执行查询
        AggregatedPage<SkuInfo> aggregatedPage = elasticsearchTemplate.queryForPage(builder.build(), SkuInfo.class);
        //11 获得总条数
        long totalCount = aggregatedPage.getTotalElements();
        //12 获得总页数
        int totalPage = aggregatedPage.getTotalPages();
        //13 获得每页的数据集合
        List<SkuInfo> skuInfoList = new ArrayList();
        //14 获取品牌的聚合查询结果
        StringTerms brandTerms = (StringTerms) aggregatedPage.getAggregation("brand");
        if (brandTerms != null) {
            brandList = brandTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
        }
        //15 获取规格的聚合查询结果
        StringTerms specTerms = (StringTerms) aggregatedPage.getAggregation("skuSpec");
        if (specTerms != null) {
            specList = specTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
        }
        //16 获取分类的聚合查询结果
        StringTerms categoryTerms = (StringTerms) aggregatedPage.getAggregation("category");
        if (categoryTerms != null) {
            categoryList = categoryTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
        }
        Map<String, Set<String>> specMap = convertListToMap(specList);
        //17 高亮查询
        elasticsearchTemplate.queryForPage(
                builder.build(), 
                SkuInfo.class, 
                new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {
                for (SearchHit hit : searchResponse.getHits()) {
                    SkuInfo skuInfo = JSON.parseObject(hit.getSourceAsString(), SkuInfo.class);
                    Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                    if (highlightFields!=null&&highlightFields.size()>0){
                        skuInfo.setName(highlightFields.get("name").getFragments()[0].toString());
                    }
                    skuInfoList.add(skuInfo);
                }
                return null;
            }
        });


        //构建返回数据
        Map<String, Object> map = new HashMap();
        map.put("totalCount", totalCount);
        map.put("totalPage", totalPage);
        map.put("skuInfoList", skuInfoList);
        map.put("brandList", brandList);
        map.put("categoryList", categoryList);
        map.put("specMap", specMap);
        return map;
    }

    /**
     * 商品搜索
     * @param searchMap
     * @return
     */
//    @Override
//    public Map<String, Object> search(Map<String, String> searchMap) {
//
//
//        NativeSearchQueryBuilder builder = buildBasicQuery(searchMap);
//
//
//        //数据搜索
//        Map<String, Object> resultMap = searchList(builder);
//        List<String> categoryList = null;
//        List<String> brandList = null;
//
//        //如果查询条件中存在分类 则不需要对分类进行分组查询
//        if (searchMap.get("category")==null){
//            //分组分类查询结果集
//            categoryList = searchCategoryList(builder);
//
//
//            //如果查询条件中存在品牌 则不需要对品牌进行分组查询
//            if (searchMap.get("brand")==null){
//                //分组品牌查询结果集
//                builder.withQuery(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("categoryName",categoryList.get(0))));
//                brandList = searchBrandList(builder);
//                builder.withQuery(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("brandName",brandList.get(0))));
//            }
//        }else{
//            //分组品牌查询结果集
//            builder.withQuery(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("categoryName",searchMap.get("category"))));
//            brandList = searchBrandList(builder);
//            builder.withQuery(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("brandName",brandList.get(0))));
//        }
//
//
//        //分组规格查询结果集
//        Map<String, Set<String>> specMap = searchSpecMap(builder);
//
//        resultMap.put("categoryList",categoryList);
//        resultMap.put("brandList",brandList);
//        resultMap.put("specMap",specMap);
//        return resultMap;
//    }


    /**
     * 根据spuId删除索引库的数据
     *
     * @param id
     */
    @Override
    public void deleteDataById(String id) {
        Result<List<Sku>> result = skuFeign.findListBySpuId(id);
        List<Sku> skuList = result.getData();

        if (skuList.size() <= 0 || skuList == null) {
            throw new RuntimeException("当前商品不存在数据 无法删除");
        }

        String jsonSkuList = JSON.toJSONString(skuList);

        List<SkuInfo> skuInfos = JSON.parseArray(jsonSkuList, SkuInfo.class);
        for (SkuInfo skuInfo : skuInfos) {
            skuMapper.deleteById(skuInfo.getId());
        }
    }


    /**
     * 构建基础的查询条件
     * @param searchMap
     * @return
     */
//    private NativeSearchQueryBuilder buildBasicQuery(Map<String,String> searchMap){
//        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
//
//        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
//
//        if (searchMap!=null&&searchMap.size()>0){
//
//            String keywords = searchMap.get("keywords");
//            String brand = searchMap.get("brand");
//            String category = searchMap.get("category");
//            String price = searchMap.get("price");
//            //如果keywords不为空
//            if (!StringUtils.isEmpty(keywords)){
//                builder.withQuery(QueryBuilders.matchQuery("name",searchMap.get("keywords")));
//            }
//
//            //如果brand不为空
//            if (!StringUtils.isEmpty(brand)){
//                boolQueryBuilder.must(QueryBuilders.termQuery("brandName",brand));
//            }
//            //如果category不为空
//            if (!StringUtils.isEmpty(category)){
//                boolQueryBuilder.must(QueryBuilders.termQuery("categoryName",category));
//            }
//
//            //判断规格
//            for (Map.Entry<String, String> entry : searchMap.entrySet()) {
//                String key = entry.getKey();
//
//                if (key.startsWith("spec.")){
//                    //如果searchMap中存在spec.的键 则说明存在规格的查询
//                    boolQueryBuilder.must(QueryBuilders.termQuery("specMap."+key.substring(5)+".keyword",searchMap.get(key)));
//                }
//            }
//
//            //判断价格条件
//            if (!StringUtils.isEmpty(price)){
//                String[] priceStr = price.replace("元","").replace("以上","").split("-");
//                boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gt(Integer.parseInt(priceStr[0])));
//                if (priceStr.length==2){
//                    boolQueryBuilder.must(QueryBuilders.rangeQuery("price").lte(Integer.parseInt(priceStr[1])));
//                }
//            }
//        }
//
//        //分页查询
//        Integer pageNum = convertPage(searchMap);//默认为第一页
//        Integer pageSize = 30;   //每页显示条数
//        builder.withPageable(PageRequest.of(pageNum,pageSize));
//
//        builder.withFilter(boolQueryBuilder);
//        return builder;
//    }

    /**
     * 数据搜索
     * @param builder
     * @return
     */
//    private Map<String,Object> searchList(NativeSearchQueryBuilder builder){
//        AggregatedPage<SkuInfo> aggregatedPage = elasticsearchTemplate.queryForPage(builder.build(), SkuInfo.class);
//
//        List<SkuInfo> skuInfos = aggregatedPage.getContent();
//        long totalNum = aggregatedPage.getTotalElements();//查询总记录数
//        int totalPages = aggregatedPage.getTotalPages();//总页数
//        Map<String,Object> map = new HashMap<>();
//        map.put("skuInfos",skuInfos);
//        map.put("totalNum",totalNum);
//        map.put("totalPages",totalPages);
//        return map;
//    }

    /**
     * 分组分类查询结果集
     * @param builder
     * @return
     */
//    private List<String> searchCategoryList(NativeSearchQueryBuilder builder){
//        /**
//         * 指定分类域 并根据分类域配置聚合查询
//         *  1.给分组指定别名
//         *  2.指定查询域
//         */
//        builder.addAggregation(AggregationBuilders.terms("skuCategory").field("categoryName"));
//
//        //执行查询
//        AggregatedPage<SkuInfo> skuPage = elasticsearchTemplate.queryForPage(builder.build(), SkuInfo.class);
//
//        //获取查询结果
//        Aggregations aggregations = skuPage.getAggregations();
//
//        StringTerms stringTerms = aggregations.get("skuCategory");
//        List<StringTerms.Bucket> termsBuckets = stringTerms.getBuckets();
//
//        //将查询结果解析 获得分类名称 放入一个集合中
//        ArrayList<String> categoryList = new ArrayList<>();
//        for (StringTerms.Bucket termsBucket : termsBuckets) {
//            categoryList.add(termsBucket.getKeyAsString());
//        }
//        return categoryList;
//    }

    /**
     * 分组品牌进行查询
     * @param builder
     * @return
     */
//    private List<String> searchBrandList(NativeSearchQueryBuilder builder){
//
//        //配置聚合查询条件
//        builder.addAggregation(AggregationBuilders.terms("skuBrand").field("brandName"));
//
//        //执行查询
//        AggregatedPage<SkuInfo> skuPage = elasticsearchTemplate.queryForPage(builder.build(), SkuInfo.class);
//
//        //解析查询结果
//        Aggregations aggregations = skuPage.getAggregations();
//        StringTerms terms = aggregations.get("skuBrand");
//
//        List<StringTerms.Bucket> termsBuckets = terms.getBuckets();
//
//        ArrayList<String> brandList = new ArrayList<>();
//        for (StringTerms.Bucket termsBucket : termsBuckets) {
//            brandList.add(termsBucket.getKeyAsString());
//        }
//        return brandList;
//    }


//    private Map<String,Set<String>> searchSpecMap(NativeSearchQueryBuilder builder){
//
//        //配置聚合查询条件
//        builder.addAggregation(AggregationBuilders.terms("skuSpec").field("spec.keyword").size(10000));
//
//        //执行查询
//        AggregatedPage<SkuInfo> skuPage = elasticsearchTemplate.queryForPage(builder.build(), SkuInfo.class);
//        //解析查询结果
//        Aggregations aggregations = skuPage.getAggregations();
//        StringTerms terms = aggregations.get("skuSpec");
//
//        List<StringTerms.Bucket> termsBuckets = terms.getBuckets();
//        ArrayList<String> specList = new ArrayList<>();
//        for (StringTerms.Bucket termsBucket : termsBuckets) {
//            //[{'颜色': '金色', '版本': '4GB+64GB'},{'颜色': '金色', '版本': '4GB+64GB'}]
//            specList.add(termsBucket.getKeyAsString());
//        }
//        Map<String,Set<String>> specMap = new HashMap();
//
//        for (String spec : specList) {
//            Map<String,String> map = JSON.parseObject(spec, Map.class);
//            for (Map.Entry<String, String> entry : map.entrySet()) {
//                String key = entry.getKey();
//                String value = entry.getValue();
//                Set<String> specValues = specMap.get(key);
//                if (specValues==null||specValues.size()==0){
//                    //如果set集合中数据为空
//                    specValues = new HashSet();
//                }
//                specValues.add(value);
//                specMap.put(key,specValues);
//            }
//        }
//        return specMap;
//    }

//    private Integer convertPage(Map<String,String> searchMap){
//        if (searchMap!=null){
//            String pageNum = searchMap.get("pageNum");
//            if (!StringUtils.isEmpty(pageNum)){
//                return Integer.parseInt(pageNum);
//            }else{
//                return 1;
//            }
//        }
//        return 1;
//    }


    /**
     * {"颜色":[],"版本":[]}
     *
     * @param specList
     * @return
     */
    public Map<String, Set<String>> convertListToMap(List<String> specList) {
        Map<String, Set<String>> resultMap = new HashMap();
        for (String spec : specList) {
            Map<String, String> map = JSON.parseObject(spec, Map.class);
            for (Map.Entry<String, String> entry : map.entrySet()) {
                String value = entry.getValue();
                String key = entry.getKey();
                Set<String> specValues = resultMap.get(key);
                if (specValues == null || specValues.size() == 0) {
                    specValues = new HashSet();
                }
                specValues.add(value);

                resultMap.put(key, specValues);
            }
        }

        return resultMap;
    }


    /**
     * 判断搜索条件中是否包含规格的查询
     *
     * @param searchMap
     * @return
     */
    public boolean ifHasSpecCondition(Map<String, String> searchMap) {
        boolean flag = false;

        for (Map.Entry<String, String> entry : searchMap.entrySet()) {
            String key = entry.getKey();
            if (key.startsWith("spec.")) {
                flag = true;
                break;
            }
        }
        return flag;
    }
}
